#ifndef AST_H
#define AST_H

enum AstNodeKind {
    NODE_NUMBER, NODE_RETURN, NODE_STRING, NODE_OPCODE_1, NODE_BINARY_OP,
    NODE_UNARY_OP, NODE_UNARY_OP_1, NODE_TWO_VALUES, NODE_CALL_1, NODE_EFUN,
};

union AstNodeOrValue {
    int number;
    struct _AstNode *expr;
};

typedef struct _AstNode {
    int id;     /* for debug */
    int kind;
    int type;
    union AstNodeOrValue v, l, r;
    struct _AstNode *next;
} AstNode;

void AstNode_Init(void);
void AstNode_FreeAllNodes(void);

int AstNode_IsNode(AstNode *self, enum AstNodeKind kind, int number);

AstNode *AstNode_CreateReturn(AstNode *right);
AstNode *AstNode_CreateString(int index);
AstNode *AstNode_CreateError(void);
AstNode *AstNode_SetError(AstNode *node);
AstNode *AstNode_CreateOpCodeWithOneArg(int op, int type, int arg);
AstNode *AstNode_CreateBinaryOp(int op, int type, AstNode *left, AstNode *right);
AstNode *AstNode_CreateUnaryOp(int op, int type, AstNode *right);
AstNode *AstNode_CreateUnaryOpWithOneArg(int op, int type, AstNode *right, int arg);
AstNode *AstNode_CreateTwoValues(int type, AstNode *left, AstNode *right);
AstNode *AstNode_CreateExprList(AstNode *right);
AstNode *AstNode_CreateExprNode(AstNode *subnode);
AstNode *AstNode_ConnectExprNodes(AstNode *chain, AstNode *subnode);
AstNode *AstNode_CallEFun(AstNode *node, int efun_id, int num_arg, int type);
AstNode *AstNode_CallFunction(AstNode *node, int index, int type);
AstNode *AstNode_PopValue(AstNode *self);

typedef struct _Code {
    char *c_start, *c_end, *c_max;
} Code;

Code *AstNode_GenerateCode(AstNode *node);
void AstNode_FreeCode(Code *code);

#endif
